/**
 *    @file       sockbase.h
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       12/21/2012 04:21:37 PM
 *
 *    @author     Theophilus (), wangtf418@gmail.com
 */
#ifndef _BF_SOCKBASE_H_
#define _BF_SOCKBASE_H_
#include <string>
#include <netinet/in.h>
#include "comdef.h"
#include "atomic_int.h"
#include "epoll.h"

class sockbase
{
public:
	sockbase();
	virtual ~sockbase();

public:
	bf_int_t socket(bf_int_t socktype); //< SOCK_STREAM, SOCK_DGRAM, SOCK_RAW...
	bf_int_t close();
	bf_int_t bind(const std::string &host, bf_ushort_t port);
	bf_int_t bind(bf_uint_t hostip, bf_ushort_t port);

public:
	bf_int_t listen(bf_int_t backlog = 1024);
	bf_int_t connect(const std::string &host, bf_ushort_t port);
	bf_int_t connect(bf_uint_t hostip, bf_ushort_t port);
	bf_int_t accept(struct sockaddr_in &addr);
	bf_int_t recv(void *recv_buf, bf_size_t buf_len, bf_int_t flag = 0);
	bf_int_t send(const void *send_buf, bf_size_t buf_len, bf_int_t flag = 0);
	bf_int_t recvfrom(void *recv_buf, bf_size_t buf_len, struct sockaddr_in &addr, bf_int_t flag = 0);
	bf_int_t sendto(const void *send_buf, bf_size_t buf_len, const std::string &host, bf_ushort_t port, bf_int_t flag = 0);
	bf_int_t sendto(const void *send_buf, bf_size_t buf_len, bf_uint_t hostip, bf_ushort_t port, bf_int_t flag = 0);
	bf_int_t sendto(const void *send_buf, bf_size_t buf_len, const struct sockaddr_in &addr, bf_int_t flag = 0);
	bf_int_t setsockopt(bf_int_t level, bf_int_t optname, const void *optval, bf_size_t optlen);
	bf_int_t getsockopt(bf_int_t level, bf_int_t optname, void *optval, bf_size_t optlen);
	bf_int_t get_socket_error();

public:
	bf_int_t set_nonblock_opt(bf_bool_t nonblock_flag = true);
	bf_int_t set_tcpnodelay_opt(bf_bool_t nodelay_flag = true);
	bf_int_t set_reuse_opt(bf_bool_t reuse_flag = true);
	bf_int_t set_recvbuf_opt(bf_int_t bufsize);
	bf_int_t set_sendbuf_opt(bf_int_t bufsize);

public:
	inline bf_int_t get_socket()
	{
		return m_socket;
	}

	inline struct sockaddr_in & get_sockaddr()
	{
		return m_addr;
	}

protected:
	bf_int_t m_socket;
	struct sockaddr_in m_addr;
};

class csocket : public sockbase
{
public:
	csocket();
	csocket(bf_uint_t hostip, bf_ushort_t port);
	csocket(bf_int_t sock, const struct sockaddr_in &addr);
	virtual ~csocket();

public:
	static inline bf_uint32_t get_socket_num()
	{
		return m_socket_num.get();
	}
	using sockbase::bind;
	bf_int_t bind()
	{
		return bind(m_hostip, m_port);
	}

public:
	inline bf_uint_t get_hostip() {return m_hostip;}
	inline bf_ushort_t get_port() {return m_port;}

protected:
	static atomic_uint32 m_socket_num;

protected:
	bf_uint_t m_hostip;
	bf_ushort_t m_port;
};

class udpclient_socket : public sockbase
{
public:
	udpclient_socket(const std::string &srvhost, bf_ushort_t srvport, const std::string &host = "0.0.0.0", bf_ushort_t port = 0);
public:
	bf_int_t init();
public:
	using sockbase::sendto;
	using sockbase::recvfrom;
	bf_int_t sendto(const void *send_buf, bf_size_t buf_len, bf_time_t timeout);
	bf_int_t recvfrom(void *recv_buf, bf_size_t buf_len, bf_time_t timeout);
protected:
	std::string m_host;
	bf_ushort_t m_port;
	std::string m_srvhost;
	bf_ushort_t m_srvport;
	struct sockaddr_in m_srv_addr;
	epoll m_epoll;
};

#endif

